'''
--- КАСТОМНЫЙ ИТЕРОАТОР (ПРОТОКОЛ ИТЕРАТОРА)---
По материалам [Итераторы в Python для самых маленьких](https://habr.com/ru/companies/domclick/articles/674194/)
Необходимость написания кастомного итератора возникает тогда, когда мы хотим тонко
управлять процессом перебора. Например, иметь возможность при каком-то событии начать 
итерацию с самого начала или установить значение указателя перебора на 
определённый элемент. То есть не перебирать всё подряд, как в цикле for,
а управлять вручную нашим процессом через непосредственное взаимодействие с 
итератором.
'''

class TumbochkaIterator:
    '''КЛАССС-ИТЕРАТОР создающий ОБЪЕКТ ИТЕРАТОРА (говорят проще - ИТЕРАТОР)'''
    def __init__(self, some_objects):
        self.some_objects = some_objects
        self.current = 0

    def to_start(self):
        '''Дополнительный метод возвращающий на курсор старт при ручной итерации'''
        self.current = 0

    def to_current(self, val):
        '''Дополнительный метод возвращающий на курсор на выбранную позицию при ручной итерации'''
        if val >= len(self.some_objects) or val < 0:
            print("Неверное значение для курсора!")
        else:
            self.current = val


    def __iter__(self):
        '''По соглашению объекты-итераторы также должны являться итерируемыми объектами,
поэтому здесь также добавляем медод __iter__'''
        return self


    def __next__(self):
        '''Добавляем магический метод __next__ для того чтобы реализовать ИТЕРАТОР.
Теперь, в качестве результата работы функции iter, от нашей тумбочки (итерируемого объекта)
будет самый настоящий ОБЪЕКТ ИТЕРАТОР! При этом он не имеет
никакого понятия из чего он вернулся — из тумбочки, ящика или грузовика. Ему об 
этом знать не нужно, его задача будет состоять лишь в том, чтобы возвращать 
очередное значение, когда его передадут в функцию next в качестве аргумента!
'''
        if self.current < len(self.some_objects):
            result = self.some_objects[self.current]
            self.current += 1
            return result
        raise StopIteration 

class Tumbochka:
    '''Класс создающий тумбочку (ИТЕРИРУЕМЫЙ ОБЪЕКТ) и позволяющий добавлять и убирать предметы в три ее ящика'''
    def __init__(self):
         self.boxes = {
             1: [],
             2: [],
             3: []
        }

    def add_to_box(self, obj, box_num):
        if box_num not in {1, 2, 3}:
            print("Вы ввели неправильный номер ящика!")
        else:
            self.boxes[box_num].append(obj)

    def remove_from_box(self, box_num):
        if box_num not in {1, 2, 3}:
            print("Вы ввели неправильный номер ящика!")
        else:
            return self.boxes[box_num].pop()

    def __str__(self):
        boxes_items = self.boxes[1] + self.boxes[2] + self.boxes[3]
        return ", ".join(boxes_items)


    def __iter__(self):
        '''Из итерируемого объекта (тумбочки) создаем ИТЕРАТОР, котороый, чтобы считаться таковым,
также должен обладать магическим методом, способным возвращать очередное значение __next__. Этот метод нужно
добавить в класс-итератор TumbochkaIterator.
'''
        return TumbochkaIterator(self.boxes[1] + self.boxes[2] + self.boxes[3])

tumb = Tumbochka() # Получаем итерирунемый объект - это объект, который можно перебирать (итерировать).
                   # Не все объекты могут быть предназначены для итерирования, а только те, что
                   # в результате вызова функции iter(итерируемый объект) возвращают объект итератора,
                   # в данном случае это объект типа list_iterator
tumb.add_to_box("ножницы", 1)
tumb.add_to_box("карандаш", 2)
tumb.add_to_box("яблоко", 2)
tumb.add_to_box("книга", 1)
it = iter(tumb) # Получаем ОБЪЕКТ ИТЕРАТОРА. Аргументом этой функции является ИТЕРИРУЕМЫЙ ОБЪЕКТ
##it.to_current(2) # Начинаем итерацию с позиции курсора = 2
##print(next(it))
##print(next(it))
####it.to_start() # Перемещаем курсор снова на старт
##print(next(it))
##print(next(it))
##print(next(it))
##print(next(it))

##print(next(it))


### Процесс итерации тумбочки в цикле for
##for el in tumb:
##    print(el)
##>>>ножницы
##>>>книга
##>>>карандаш
##>>>яблоко

# Процесс итерации тумбочки в цикле for начиная с курсора = 2
it.to_current(2)
for el in it:
    print(el)
##>>>карандаш
##>>>яблоко
